1. Field of the Invention
The invention relates generally to the management of the resources used by a computer program in the course of its execution and more specifically to the prevention of resource leaks. A resource leak occurs when a program is finished using a resource but does not free it for use by other programs.
2. Description of the Prior Art: FIGS. 1 and 2
A program that is executing on a computer system uses resources provided by the computer system. The resources include memory and non-memory resources such as files and input-output devices. In many cases, access to these non-memory resources is provided by the operating system, which itself maintains data structures representing these resources
Leaks may occur with any of these resources. Memory leaks have long been dealt with by garbage collectors, that is, programs which check for memory which was allocated by a program but is no longer being used by the program and may therefore be freed for use by other programs. A successful commercial example of a garbage collector is the Great Circle(trademark) garbage collector, manufactured by Geodesic Systems, Inc. An overview of this garbage collector was available on Feb. 22, 1999 at http://www.geodesic.com/greatcircle/overview.html. The Great Circle garbage collector works not only with programs specifically coded to be run with it, but also with programs that were not coded to be run with it, and can thus be used with legacy programs, that is, programs that are still useful but cannot be economically reimplemented to take advantage of innovations such as garbage collectors.
Non-memory resources pose a problem for garbage collectors. FIG. 1 shows why. The figure shows a program that is written in an object-oriented programming language such as C++ as the program is being executed in a computer system. In object-oriented programming languages, the program manipulates objects, that is, entities which belong to classes. The class to which an object belongs defines a fixed set of operations that may be performed on the class. FIG. 1 shows how such programs are typically implemented. Code 107 for the program consists of code 111 for a main program and code 113 for the operations for the classes of objects which are used by main program code 111 and code 113. One set of code for objects of class N is shown at 115. Included in the operations defined for a class are a constructor operation 117, which performs the actions necessary to construct an object of the class, and a destructor operation 119, which performs any actions that need be done before the storage for an object of the class is freed. The destructor operation is an example of a finalizer operation, namely an operation that a garbage collector must perform before it reclaims an object""s storage.
A single object of class N is shown at 121. The object has two parts: specifiers 123 for the operations defined for its class, and the data 125 upon which these operations are performed. In the case of objects of class N, the data includes a font descriptor, a value provided by the operating system to specify a font used by the program. Font descriptor 127 is used by operations of class N that involve functions provided by an operating system font engine, shown at 129. When given a character code, a size specification, and a font descriptor 121, font engine 129 can generate a representation of the character of the specified size in the specified font. In order to accelerate generation of these representations, font engine 129 makes a rendering 131 of the font which it stores in its address space 105. Once the rendering is made, font engine 129 can find the representation by looking it up in the rendering. The font descriptor and its related rendering are examples of non-memory resources. The rendering in particular is large, and efficient operation of the operating system requires that renderings 131 be released when they are no longer required by a program. The following discussion primarily concerns non-memory resources, and unless otherwise indicated, a reference to a xe2x80x9cresourcexe2x80x9d will be understood to be a reference to a non-memory resource.
One of the functions of a class""s destructor is to ensure that all resources used by the object are released when the object is destroyed. Thus, destructor 119 for objects of class N 115 includes a call to the operating system which indicates to font engine 129 that font descriptor 127 and its associated rendering 131 may be released for use by other programs. Of course, if the programmer forgets to expressly free object 121, its destructor will never be executed and not only object 121, but also font descriptor 127 and rendering 131 will have leaked.
As can be seen from FIG. 1, having a garbage collector detect that object 121 is no longer in use and freeing object 121 will not by itself solve the problem of the leaked non-memory resources. The garbage collector can free object 121""s memory, but since the garbage collector is in general not in a position to know anything about object 121""s class or about the contents of its memory, it will not execute destructor 119 when it frees object 121 ""s memory, and as far as font engine 129 can determine, both font descriptor 127 and rendering 131 are still in use.
In prior art garbage collectors, this problem has been solved by providing registration functions that explicitly indicate to the garbage collector that a destructor is to be executed when an object is freed. When the programmer writes a program that allocates an object for which a destructor must be executed when the object is freed, the code that allocates the object includes the registration function. FIG. 2 shows two examples of such code. The first example, at 201, is written in C; the programmer has written a noisyCleanup function 203 which is to be executed when certain objects are freed. At 205, an object ip is allocated using the malloc function; immediately following this function call, at 207, the programmer has made a call to the gcDeclareFinalizer registration function. This function, which takes the object and the cleanup function as arguments, registers the cleanup function with the garbage collector (in this case, a Great Circle garbage collector).
The result of registration is the creation of an entry for the object in a registration table 209 maintained by the garbage collector. Each registration entry (RTE) 211 in the table specifies two items of information: an object pointer 213, which points to the object whose allocation resulted in creation of the entry, and finalizer pointer 215, which points to the destructor 119 for the object""s class. Before freeing an object, the garbage collector searches registration table 209 for a RTE 211 that contains a pointer 213 to the object; if it finds one, it executes the code specified by finalizer pointer 215 in the entry before it frees the object.
Continuing with FIG. 2, 217 shows how a C++ programmer would specify that an object be registered. Because C++ is an object-oriented language, the programmer must specify an object""s finalizer as part of its class definition. The #include compiler directive at 219 specifies that the file xe2x80x9cgct.hxe2x80x9d that contains the class information for the registration operation gcCleanup be included in this file, making the name gcCleanup visible here. The statement at 221 adds gcCleanup to the definition of the class A and defines it for that class. For class A, inheriting from gcCleanup defines the finalizer for class A as the destructor for class A, namely xcx9cA ( ), which is in turn defined to be whatever code is written where cleanup action appears. As a result of this code, every time an object of class A is allocated in a program execution, the object is registered in registration table 209, with finalizer pointer 215 pointing to the code that does the action defined for xcx9cA.
While registration solves the problem of ensuring that a garbage collector not only prevents memory leaks, but also prevents leaks of non-memory resources, registration as presently practiced has two problems:
Since the code specifying registration must be in the program when the program is written, garbage collectors that are used with legacy programs to collect garbage cannot register objects and therefore cannot execute finalization code for the objects.
Even where the programmer is writing new code for execution with a garbage collector, the programmer must still remember to include registration code in the class definition for every object that requires finalization before the object is freed.
What is needed is a technique for making garbage collection of non-memory resources as automatic from the programmer""s viewpoint as garbage collection of memory already is. Such a technique would not only make garbage collection of non-memory resources possible with legacy code, but would also relieve the programmer of the burden of concerning him or herself with it when writing new programs. It is an object of the invention to provide such a technique.
The technique of the invention automatically determines by examining a program that the program will use the resource and then automatically modifies the program""s behavior such that the program""s execution makes an entry for the resource in a registry. When it is determined that the execution no longer requires the resource, the entry in the registry indicates that the resource is to be released.
The technique of the invention may also be employed to ensure that finalizers associated with objects are executed. The technique automatically determines from the program being executed that the program will use an object and then automatically modifies the program""s behavior such that the program""s execution makes an entry for the finalizer in the registry. When it is determined that the execution no longer requires the object, the entry indicates that the finalizer that is to be executed in conjunction with freeing the object. One frequent use of a finalizer is to free a resource associated with the object.
Modification of the behavior of the program may be done at any time up through the execution of the program. One way of modifying the program""s behavior is to replace a call to a function whose execution entails allocating an object or a resource with a call to a registration function that makes the entry in the registry and then calls the originally-intended function.
The technique may be particularly advantageously employed in conjunction with a garbage collector. The garbage collector performs the actions necessary to modify the behavior of the program and whenever the garbage collector frees an object that is no longer used by the program, the garbage collector executes the object""s finalizer if there is an entry for the object in the registry.